using System;
using System.Collections.Generic;
using OracleInternal.Common;
using OracleInternal.Network;
using OracleInternal.ServiceObjects;

namespace OracleInternal.TTC.Accessors
{
	internal class TTCLongAccessor : Accessor
	{
		internal const int MAX_LENGTH = int.MaxValue;

		internal const int DEFAULT_FETCH_SIZE = 4080;

		internal int m_longFetchSize;

		private int m_escapeSequence;

		private bool m_readHeader;

		private bool m_readAsNonStream;

		internal TTCLongAccessor(ColumnDescribeInfo colMetaData, MarshallingEngine marshallingEngine, bool bForBind, int initialLongFetchSize)
			: base(colMetaData, marshallingEngine, bForBind)
		{
			m_byteLength = 0;
			m_longFetchSize = initialLongFetchSize;
			m_bNullByDescribe = false;
			if (m_totalLengthOfData == null)
			{
				m_totalLengthOfData = new List<int>();
			}
		}

		internal override void Initialize(ColumnDescribeInfo colMetaData, MarshallingEngine marshallingEngine, bool bForBind)
		{
			base.Initialize(colMetaData, marshallingEngine, bForBind);
			m_bNullByDescribe = false;
		}

		internal int UnmarshalHelper(DataUnmarshaller dataUnmarshaller, int currentRow, int columnIndex)
		{
			int num = 0;
			m_escapeSequence = dataUnmarshaller.UnmarshalUB1();
			if (dataUnmarshaller.EscapeSequenceNull(m_escapeSequence))
			{
				throw new Exception("Not expected here for NULL value");
			}
			m_readHeader = true;
			m_readAsNonStream = false;
			int num2 = 0;
			while (num2 != -1)
			{
				num2 = ReadStreamLocally(dataUnmarshaller);
				if (num2 != -1)
				{
					num += num2;
				}
			}
			return num;
		}

		private int ReadStreamLocally(DataUnmarshaller dataUnmarshaller)
		{
			int num = -1;
			try
			{
				if (!m_readAsNonStream)
				{
					if (!m_readHeader)
					{
						num = ((!dataUnmarshaller.m_bUseBigCLRChunks) ? dataUnmarshaller.UnmarshalUB1() : dataUnmarshaller.UnmarshalSB4());
					}
					else
					{
						if (m_escapeSequence == 254)
						{
							num = ((!dataUnmarshaller.m_bUseBigCLRChunks) ? dataUnmarshaller.UnmarshalUB1() : dataUnmarshaller.UnmarshalSB4());
						}
						else
						{
							if (m_escapeSequence == 0)
							{
								return 0;
							}
							m_readAsNonStream = true;
							num = m_escapeSequence;
						}
						m_readHeader = false;
						m_escapeSequence = 0;
					}
				}
				else
				{
					m_readAsNonStream = false;
				}
				if (num > 0)
				{
					dataUnmarshaller.UnmarshalBuffer_ScanOnly(num);
					return num;
				}
				num = -1;
				return num;
			}
			catch
			{
				return num;
			}
		}

		internal long FillDataInUserBuffer(DataUnmarshaller dataUnmarshaller, int currentRow, int columnIndex, long fieldOffset, byte[] buffer, int bufferOffset, int length)
		{
			long result = 0L;
			if (m_longFetchSize == 0)
			{
				return result;
			}
			try
			{
				dataUnmarshaller.StartAccumulatingColumnData(currentRow, columnIndex, m_colDataSegments);
				int num = UnmarshalHelper(dataUnmarshaller, currentRow, columnIndex);
				if (num > 0)
				{
					if (buffer != null)
					{
						long num2 = buffer.Length - bufferOffset;
						long num3 = num - fieldOffset;
						long num4 = ((num2 < num) ? num2 : num);
						long num5 = ((num4 < num3) ? num4 : num3);
						if (num5 > 0)
						{
							result = num5;
							Accessor.CopyDataToUserBuffer(m_colDataSegments, (int)fieldOffset, buffer, bufferOffset, (int)num5);
							return result;
						}
						return result;
					}
					return num - fieldOffset;
				}
				return result;
			}
			finally
			{
				m_colDataSegments.Clear();
				dataUnmarshaller.m_bAccumulateByteSegments = false;
				dataUnmarshaller.m_dataSegments = null;
			}
		}

		internal long FillDataInUserBuffer(DataUnmarshaller dataUnmarshaller, int currentRow, int columnIndex, long fieldOffset, char[] buffer, int bufferOffset, int numCharsToCopy)
		{
			int charCount = 0;
			if (m_longFetchSize == 0)
			{
				return charCount;
			}
			try
			{
				dataUnmarshaller.StartAccumulatingColumnData(currentRow, columnIndex, m_colDataSegments);
				int num = UnmarshalHelper(dataUnmarshaller, currentRow, columnIndex);
				if (num > 0)
				{
					if (buffer != null)
					{
						long num2 = buffer.Length - bufferOffset;
						long num3 = num - fieldOffset;
						long num4 = ((num2 < numCharsToCopy) ? num2 : numCharsToCopy);
						int num5 = (int)((num4 < num3) ? num4 : num3);
						if (num5 > 0)
						{
							charCount = num5;
							int bytesOffset = (int)fieldOffset;
							if (m_marshallingEngine.m_dbCharSetConv.MaxBytesPerChar > 1 && fieldOffset > 0)
							{
								bytesOffset = m_marshallingEngine.m_dbCharSetConv.GetBytesOffset(m_colDataSegments, (int)fieldOffset);
							}
							num5 = m_marshallingEngine.m_dbCharSetConv.ConvertBytesToChars(m_colDataSegments, bytesOffset, num, buffer, bufferOffset, ref charCount);
						}
					}
					else
					{
						int bytesOffset2 = (int)fieldOffset;
						if (m_marshallingEngine.m_dbCharSetConv.MaxBytesPerChar > 1 && fieldOffset > 0)
						{
							bytesOffset2 = m_marshallingEngine.m_dbCharSetConv.GetBytesOffset(m_colDataSegments, (int)fieldOffset);
						}
						charCount = m_marshallingEngine.m_dbCharSetConv.GetCharsLength(m_colDataSegments, bytesOffset2, num);
					}
				}
			}
			finally
			{
				m_colDataSegments.Clear();
				dataUnmarshaller.m_bAccumulateByteSegments = false;
				dataUnmarshaller.m_dataSegments = null;
			}
			return charCount;
		}

		internal override byte[] GetByteRepresentation(DataUnmarshaller dataUnmarshaller, int currentRow, int columnIndex)
		{
			byte[] result = null;
			try
			{
				dataUnmarshaller.StartAccumulatingColumnData(currentRow, columnIndex, m_colDataSegments);
				int num = UnmarshalHelper(dataUnmarshaller, currentRow, columnIndex);
				if (num > 0)
				{
					result = new byte[num];
					Accessor.CopyDataToUserBuffer(m_colDataSegments, 0, result, 0, num);
					return result;
				}
				return result;
			}
			finally
			{
				m_colDataSegments.Clear();
				dataUnmarshaller.m_bAccumulateByteSegments = false;
				dataUnmarshaller.m_dataSegments = null;
			}
		}

		internal override string GetString(DataUnmarshaller dataUnmarshaller, int currentRow, int columnIndex)
		{
			return GetString(dataUnmarshaller, currentRow, columnIndex, 1);
		}

		internal override string GetString(DataUnmarshaller dataUnmarshaller, int currentRow, int columnIndex, byte charSetForm)
		{
			string empty = string.Empty;
			if (m_longFetchSize == 0)
			{
				return empty;
			}
			try
			{
				dataUnmarshaller.StartAccumulatingColumnData(currentRow, columnIndex, m_colDataSegments);
				int num = UnmarshalHelper(dataUnmarshaller, currentRow, columnIndex);
				if (num > 0)
				{
					if (charSetForm == 2)
					{
						char[] charArrayForConversion = dataUnmarshaller.GetCharArrayForConversion(num, m_marshallingEngine.m_nCharSetConv);
						return m_marshallingEngine.m_nCharSetConv.ConvertBytesToString(m_colDataSegments, 0, num, charArrayForConversion);
					}
					char[] charArrayForConversion2 = dataUnmarshaller.GetCharArrayForConversion(num, m_marshallingEngine.m_dbCharSetConv);
					return m_marshallingEngine.m_dbCharSetConv.ConvertBytesToString(m_colDataSegments, 0, num, charArrayForConversion2);
				}
				return empty;
			}
			finally
			{
				m_colDataSegments.Clear();
				dataUnmarshaller.m_bAccumulateByteSegments = false;
				dataUnmarshaller.m_dataSegments = null;
			}
		}

		internal long GetBytes(DataUnmarshaller dataUnmarshaller, int currentRow, int columnIndex, long fieldOffset, byte[] buffer, int bufferOffset, int length)
		{
			return FillDataInUserBuffer(dataUnmarshaller, currentRow, columnIndex, fieldOffset, buffer, bufferOffset, length);
		}

		internal long GetChars(DataUnmarshaller dataUnmarshaller, int currentRow, int columnIndex, long fieldOffset, char[] buffer, int bufferOffset, int length)
		{
			return FillDataInUserBuffer(dataUnmarshaller, currentRow, columnIndex, fieldOffset, buffer, bufferOffset, length);
		}

		internal override void UnmarshalColumnData()
		{
			int num = 0;
			try
			{
				m_marshallingEngine.m_oraBufRdr.m_bParsingColumnData = true;
				m_marshallingEngine.m_oraBufRdr.m_bMarkStartOffsetForColData = true;
				m_escapeSequence = m_marshallingEngine.UnmarshalUB1();
				if (m_marshallingEngine.EscapeSequenceNull(m_escapeSequence))
				{
					m_marshallingEngine.ProcessIndicator(isNull: false, 0);
					m_marshallingEngine.UnmarshalUB4();
					return;
				}
				m_readHeader = true;
				m_readAsNonStream = false;
				int num2 = 0;
				while (num2 != -1)
				{
					num2 = ReadStreamFromWire_ScanOnly();
					if (num2 != -1)
					{
						num += num2;
					}
				}
			}
			finally
			{
				m_marshallingEngine.m_oraBufRdr.m_bParsingColumnData = false;
				m_marshallingEngine.m_oraBufRdr.m_bMarkStartOffsetForColData = false;
				m_totalLengthOfData.Add(num);
				if (num <= 0)
				{
					m_marshallingEngine.m_oraBufRdr.m_colDataStartOffset[m_marshallingEngine.m_oraBufRdr.m_colDataStartOffsetIndexToUpdate] = -1;
				}
				m_lastRowProcessed++;
			}
		}

		internal override bool UnmarshalOneRow()
		{
			int num = 0;
			bool flag = true;
			try
			{
				flag = m_marshallingEngine.m_oraBufRdr.StartAccumulatingColumnData(m_RowDataSegments, m_lastRowProcessed);
				m_escapeSequence = m_marshallingEngine.UnmarshalUB1();
				if (m_marshallingEngine.EscapeSequenceNull(m_escapeSequence))
				{
					m_marshallingEngine.ProcessIndicator(isNull: false, 0);
					m_marshallingEngine.UnmarshalUB4();
				}
				else
				{
					m_readHeader = true;
					m_readAsNonStream = false;
					int num2 = 0;
					while (num2 != -1)
					{
						num2 = ReadStreamFromWire_ScanOnly();
						if (num2 != -1)
						{
							num += num2;
						}
					}
				}
			}
			finally
			{
				if (flag)
				{
					m_RowDataSegments.Add(m_marshallingEngine.m_oraBufRdr.m_dataSegments);
					m_totalLengthOfData.Add(num);
				}
				else
				{
					m_RowDataSegments[m_lastRowProcessed] = m_marshallingEngine.m_oraBufRdr.m_dataSegments;
					m_totalLengthOfData[m_lastRowProcessed] = num;
				}
				m_marshallingEngine.m_oraBufRdr.StopAccumulatingColumnData();
				m_lastRowProcessed++;
			}
			return false;
		}

		private int ReadStreamFromWire_ScanOnly()
		{
			int num = -1;
			try
			{
				if (!m_readAsNonStream)
				{
					if (!m_readHeader)
					{
						num = ((!m_marshallingEngine.m_bUseBigCLRChunks) ? m_marshallingEngine.UnmarshalUB1() : m_marshallingEngine.UnmarshalSB4());
					}
					else
					{
						if (m_escapeSequence == 254)
						{
							num = ((!m_marshallingEngine.m_bUseBigCLRChunks) ? m_marshallingEngine.UnmarshalUB1() : m_marshallingEngine.UnmarshalSB4());
						}
						else
						{
							if (m_escapeSequence == 0)
							{
								return 0;
							}
							m_readAsNonStream = true;
							num = m_escapeSequence;
						}
						m_readHeader = false;
						m_escapeSequence = 0;
					}
				}
				else
				{
					m_readAsNonStream = false;
				}
				if (num > 0)
				{
					m_marshallingEngine.UnmarshalNBytes_ScanOnly(num);
				}
				else
				{
					num = -1;
				}
			}
			catch (NetworkException)
			{
				num = m_marshallingEngine.UnmarshalSB1();
				if (num == 4)
				{
					m_marshallingEngine.TTCErrorObject.Initialize();
					m_marshallingEngine.TTCErrorObject.ReadErrorMessage();
				}
			}
			if (num == -1)
			{
				m_readHeader = true;
				m_marshallingEngine.UnmarshalUB2();
				m_marshallingEngine.UnmarshalUB2();
			}
			return num;
		}

		internal bool IsCompleteDataAvailable(int currentRow)
		{
			if (m_longFetchSize == -1)
			{
				return true;
			}
			if (m_longFetchSize != 0)
			{
				return m_totalLengthOfData[currentRow] != m_longFetchSize;
			}
			return false;
		}

		internal int AvailableDataSize(int currentRow)
		{
			if (m_longFetchSize != 0)
			{
				return m_totalLengthOfData[currentRow];
			}
			return m_longFetchSize;
		}
	}
}
